package experiment;

import heuristics.AmbitiousStudentHeuristic;
import heuristics.IHeuristic;
import heuristics.LazyStudentHeuristic;
import heuristics.WorkingStudentHeuristic;

import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import log.Log;

import Entities.Calendar;
import Entities.CoursesConfiguration;
import algorithms.HillClimbing;
import algorithms.IAlgorithm;
import algorithms.RandomRestartHC;
import algorithms.RandomWalkHC;
import algorithms.TYPE_OF_RANDOM_WALK;


public class BestAlgoExperiment extends BaseExperiment {
	final static String[] logLabels = {"Heuristic", "Algorithm", "Number of Heuristic Calls", 
		"Average Heuristic Value", "Average Number of Heuristic Calls to Best"};
	final static int[] numberOfHeuristicCalls = {5000, 10000, 50000};
	final static String logPath = "experiments_output/BestAlgoExperimentResult.csv";
	static List<IHeuristic> heuristics;
	static List<IAlgorithm> algorithms;
	static Log log;
	
	public BestAlgoExperiment() {
		try {
			log = new Log(logPath);
			log.writeLabels(logLabels);
			setCourseConfigurations("coursesConfigurations");
		} catch (IOException e) {
			e.printStackTrace();
		}

		heuristics = new LinkedList<IHeuristic>();
		heuristics.add(new LazyStudentHeuristic());
		heuristics.add(new AmbitiousStudentHeuristic());
		heuristics.add(new WorkingStudentHeuristic());
		
		algorithms = new LinkedList<IAlgorithm>();
		algorithms.add(new HillClimbing());
		algorithms.add(new RandomRestartHC());
		algorithms.add(new RandomWalkHC());
		
		RandomRestartHC.setSizeOfRandomCalendar(5);
		RandomWalkHC.setTypeOfRandomWalk(TYPE_OF_RANDOM_WALK.FIXED);
		RandomWalkHC.setFixedNumberOfRandomWalk(3);
	}
	
	public void Execute() {
		System.out.println("Experiment Started: " + getDateTime());
		
		Calendar currCalendar;
		double averageHeuristicValue = 0;
		int averageNumberOfHeuristicCallsToBest = 0;

		for (IHeuristic iHeuristic : heuristics) {
			Calendar.setHeuristic(iHeuristic);
			for (IAlgorithm algo : algorithms) {
				for (int i = 0; i < numberOfHeuristicCalls.length; i++) {
					algo.setMaxOfHeuristicCalls(numberOfHeuristicCalls[i]);
					averageHeuristicValue = 0;
					averageNumberOfHeuristicCallsToBest = 0;
					for (CoursesConfiguration config : courseConfigurations) {
						Calendar.init(config.getCoursesConfiguration());
						for (int j = 0; j < NUMBER_OF_REPETED_EXECUTIONS; j++) {
							algo.reset(); // reset variables in algorithm
							currCalendar = algo.searchLocal();
							averageHeuristicValue += currCalendar.getHeuristicValue();
							averageNumberOfHeuristicCallsToBest += algo.getNumberOfHeuristicCallsToBest();
						}
					}
					averageHeuristicValue /= (double)(NUMBER_OF_REPETED_EXECUTIONS*courseConfigurations.size());
					averageNumberOfHeuristicCallsToBest /= (double)(NUMBER_OF_REPETED_EXECUTIONS*courseConfigurations.size());
					WriteToLog(iHeuristic.toString(), algo.toString(), numberOfHeuristicCalls[i], 
							averageHeuristicValue, averageNumberOfHeuristicCallsToBest);
				}
				System.out.println("Heuristic = " + iHeuristic.toString() + ", Algorithm = " + algo.toString());
			}
		}
		
		System.out.println("Experiment Ended: " + getDateTime());
		
		try {
			log.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void WriteToLog(String heuristicName, String algoName, int numberOfHeuristicCalls,
			double averageHeuristicValue, int averageNumberOfHeuriticCallsToBest) {
		HashMap<String, String> data = new HashMap<String, String>();
		data.put("Heuristic", heuristicName);
		data.put("Algorithm", algoName);
		data.put("Number of Heuristic Calls", String.valueOf(numberOfHeuristicCalls));
		data.put("Average Heuristic Value", String.valueOf(averageHeuristicValue));
		data.put("Average Number of Heuristic Calls to Best", String.valueOf(averageNumberOfHeuriticCallsToBest));
		try {
			log.writeData(data);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
